home *** CD-ROM | disk | FTP | other *** search
- // DRAW.CPP - the system-independent graphics portion of RARS 0.39
- // (was GRAPHICS.CPP) - by Mitchell E. Timin, State College, PA
- // See GI.H, CAR.H & TRACK.H for class and structure declarations.
- // This version is for Borland C++, version 3.1, and is for DOS.
- // This is part of version 0.39 of RARS (Robot Auto Racing Simulation).
- // GI.CPP is the system-dependent graphics portion of RARS.
- // ver. 0.1 release January 12, 1995
- // ver. 0.2 1/23/95
- // ver. 0.3 2/7/95
- // ver. 0.39 3/6/95
-
- /*
- * Modifications made:
- *
- * - l. 143 : Symbol 'errorcode' was not used and has been removed.
- */
-
- #include <conio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include "car.h"
- #include "track.h"
-
- static double finish_x, finish_y; // These four variables are used to locate
- static double finish_y_in, finish_y_out; // the finish line on the screen.
- static double spacing; // see leaders()
-
- extern Car* pcar[]; // array of pointers to the various cars
- extern int done_count; // how many cars have finished the race
- extern int lap_count; // how many laps is this race?
- extern int car_count; // how many cars in the race
- extern double length; // total lenth of track (average of inner and outer rails)
- extern char* namptr[]; // array of pointers to their name strings
- extern int* order; // will point to array of positions
- extern double CHR_HGT; // height in feet of row of text
- extern int no_display;
-
- int round(double given) // convert double to int by rounding
- {
- if(given > 0.0)
- return int(given + .5);
- else
- return int(given - .5);
- }
-
- // Convert input into an ASCII string with two decimal digits.
- void make_dec_string(char* out, // pointer to destination string
- double input) // value to be converted
- {
- long int value;
- char intpart[5], decpart[4];
-
- value = (long int)(100.0 * input + .5);
- itoa(int(value / 100), intpart, 10);
- itoa(int(value % 100), decpart, 10);
- if(decpart[1] == '\0') { // we might have to stick in a leading zero:
- decpart[2] = '\0';
- decpart[1] = decpart[0];
- decpart[0] = '0';
- }
- strcpy(out, intpart);
- strcat(out, ".");
- strcat(out, decpart);
- }
-
- // Assemble a string for the average speed of car i. (goes to char* out)
- void get_avg_spd(int i, char* out)
- {
- make_dec_string(out, pcar[i]->speed_avg * MPH_FPS);
- }
-
- // Assemble a string for the maximum speed of car i. (goes to char* out)
- void get_max_spd(int i, char* out)
- {
- make_dec_string(out, pcar[i]->speed_max * MPH_FPS);
- }
-
- /* new routine: draw_arc() routine that uses draw_line() to draw the arc */
- #define LINESEG_LENGTH 10 /* this constant can be used to tweak the precision */
- void draw_arc(double radius, double center_x, double center_y, double start_angle, double length)
- {
- double a;
- double stepsize;
- double x1, y1, x2, y2;
-
- /* convert a right turn so it is consistent with the left turn */
- if (radius < 0.0)
- {
- radius = -radius;
-
- start_angle = start_angle - length - PI;
- while (start_angle < 0.0)
- {
- start_angle += (2 * PI);
- }
- }
-
- /* calculate the starting point */
- x1 = center_x + radius * sin(start_angle);
- y1 = center_y - radius * cos(start_angle);
-
- /* determine the step size */
- stepsize = LINESEG_LENGTH * (1.0 / (radius * SCALE));
-
- /* draw lines over the length from there, adapting the number of steps to the length */
- for (a = stepsize; a < length; a += stepsize)
- {
- /* calculate the end point of this line */
- x2 = center_x + radius * sin(start_angle + a);
- y2 = center_y - radius * cos(start_angle + a);
-
- /* draw the line */
- draw_line(x1, y1, x2, y2);
-
- /* make the end point the new starting point for the next line */
- x1 = x2;
- y1 = y2;
- }
-
- /* calculate the end point of the arc */
- x2 = center_x + radius * sin(start_angle + length);
- y2 = center_y - radius * cos(start_angle + length);
-
- /* draw the last line */
- draw_line(x1, y1, x2, y2);
- }
-
- // Draws the path specified by the segment array and starting
- // conditions which are given as parameters. Also, fills in the
- // un-initialized portions of the segment array. Returns the length.
- double drawpath(double xstart, // coordinates of starting point
- double ystart,
- double alfstart, // starting tangent angle
- segment *track) // pointer to structure that defines path
- {
- double length = 0; // to accumulate total length of path
- double cenx, ceny; // center of circle arc
- double radius; // radius of circle arc (negative == rt. turn)
- double x, y, alf; // position and direction of start of segment
- double newx, newy, newalf; // and the one after that (alf in radians)
- int i;
-
- x = xstart; y = ystart; // store starting point & direction
- alf = alfstart;
-
- for(i=0; i < NSEG; i++) { // for each segment:
- radius = track[i].radius;
- if(radius == 0.0) { // is this a straightaway?
- length += track[i].length;
- newx = x + track[i].length * cos(alf); // find end coordinates
- newy = y + track[i].length * sin(alf);
- track[i].end_x = newx; track[i].end_y = newy; // fill in these
- track[i].beg_x = x; track[i].beg_y = y; // empty slots in
- track[i].beg_ang = track[i].end_ang = alf; // the track array
- newalf = alf; // direction won't change
- if(!no_display)
- draw_line(x, y, newx, newy); // draw the straight line
- if(i == 0) { // find pixel locations of start/finish line:
- finish_y = newy; // assume straightaway parallel to x-axis
- finish_x = x + FINISH * length;
- }
- }
- else if(radius > 0.0) {
- length += radius * track[i].length;
- cenx = x - radius * sin(alf); // compute center location:
- ceny = y + radius * cos(alf);
- track[i].cen_x = cenx; track[i].cen_y = ceny; // fill empty slots
- track[i].beg_ang = alf;
- newalf = alf + track[i].length; // compute new direction
- track[i].end_ang = newalf; // fill this empty slot
- newx = cenx + radius * sin(newalf); // location of end
- newy = ceny - radius * cos(newalf);
- track[i].end_x = newx; track[i].end_y = newy; // fill in these
- track[i].beg_x = x; track[i].beg_y = y; // empty slots
- if(!no_display)
- draw_arc(radius, cenx, ceny, alf, track[i].length); // draw the arc
- }
- else {
- length -= radius * track[i].length;
- cenx = x - radius * sin(alf); // compute center location:
- ceny = y + radius * cos(alf);
- track[i].cen_x = cenx; track[i].cen_y = ceny; // fill empty slots
- track[i].beg_ang = alf;
- newalf = alf - track[i].length; // compute new direction
- track[i].end_ang = newalf; // fill this empty slot
- newx = cenx + radius * sin(newalf); // location of end
- newy = ceny - radius * cos(newalf);
- track[i].end_x = newx; track[i].end_y = newy; // fill in these
- track[i].beg_x = x; track[i].beg_y = y; // empty slots
- if(!no_display)
- draw_arc(radius, cenx, ceny, alf, track[i].length); // draw the arc
- }
- x = newx; // repeat with new position and direction:
- y = newy;
- alf = newalf;
- }
- /* to close the circuit, we draw a line from the last point back to the first */
- /* this usually is not necessary, but it prevents flood fill leaking */
- if (!no_display)
- draw_line(x, y, xstart, ystart);
-
- return length; // return the length of the path
- }
-
- // Draw a little car on the screen, at given position and orientation,
- // and with the given colors. (to erase the car, call it with track_color)
- // returns a graphics error code, usually grOk, which is 0.
- void drawcar(double x, // coordinates of center of car
- double y,
- double ang, // orientation angle of car, wrt x-axis, radians
- int nose, // color of front portion
- int tail) // color of rear portion
- {
- double xx, yy, endx, endy;
- double sine, cosine, dx, dy;
- int i;
-
- sine = sin(ang); cosine = cos(ang);
- xx = x + cosine * CARLEN/2 - sine * CARWID/2; // left front corner coords
- yy = y + cosine * CARWID/2 + sine * CARLEN/2;
- x = xx; y = yy; // save the above values
- dx = 0.3333 * CARWID * sine;
- dy = -.3333 * CARWID * cosine;
- // below we draw three parallel lines to form the body of the car:
- set_color(tail);
- for(i=0; i<=3; i++) {
- endx = xx - CARLEN * cosine;
- endy = yy - CARLEN * sine;
- draw_line(xx, yy, endx, endy);
- if(i == 3) break;
- xx += dx;
- yy += dy;
- }
- // now three short lines of the nose color to decorate the front:
- set_color(nose);
- xx = x; yy = y; // restore x and y to left front of car
- for(i=0; i<=3; i++) {
- endx = xx + CARWID * sine;
- endy = yy - CARWID * cosine;
- draw_line(xx, yy, endx, endy);
- if(i == 3) break;
- xx += dy;
- yy -= dx;
- }
- }
-
- void lapper(int which, int lap) // shows lap count on scoreboard,
- { // also returns lap+1 to advance the lap count
- char string[] = " "; // and also increments done_count
-
- if(lap < 0)
- lap = 0;
-
- set_fill_color(FIELD_COLOR); // the green part is off the track
- // This bar erases the previous lap count:
- rectangle(SCORE_BOARD_X + 10*CHR_WID,
- SCORE_BOARD_Y - which*CHR_HGT,
- SCORE_BOARD_X + 13*CHR_WID,
- SCORE_BOARD_Y - (which+.9)*CHR_HGT);
-
- set_color(TEXT_COLOR); // now print text in black:
- itoa(lap, string, 10);
- text_output(SCORE_BOARD_X + 10 * CHR_WID,
- SCORE_BOARD_Y - which * CHR_HGT, string);
- }
-
- void border(void)
- {
- set_color(RAIL_COLOR);
- draw_line(0.0, 0.0, X_MAX, 0.0);
- draw_line(X_MAX, 0.0, X_MAX, Y_MAX);
- draw_line(X_MAX, Y_MAX, 0.0, Y_MAX);
- draw_line(0.0, Y_MAX, 0.0, 0.0);
- }
-
- // Initializes graphics system, draws track, fills in colored regions:
- void graph_setup(void)
- {
- double alt_len; // used in deciding the length of the track
-
- build_track(); // read track data and fill in trackou[], trackin[]
- if(!no_display) {
- initialize_graphics();
- /* instead of flood filling everything, we draw a rectangle */
- set_fill_color(FIELD_COLOR);
- rectangle(0.0, Y_MAX, X_MAX, 0.0);
- border(); // draw border at screen boundary
- // paint the whole screen green:
- /*set_fill_color(FIELD_COLOR);*/
- /*flood_fill(20.0, 20.0);*/
- }
- // draw outer track boundary:
- length = drawpath(TRK_STRT_X, TRK_STRT_Y, 0, trackout);
- finish_y_out = finish_y; // locate one end of finish line
- // draw inner track boundary:
- alt_len = drawpath(TRK_STRT_X, TRK_STRT_Y+width, 0, trackin);
- if(alt_len < length) // take length of shorter rail as track length
- length = alt_len;
- finish_y_in = finish_y; // locate other end of finish line
- if(no_display)
- return;
- // pave the track:
- set_fill_color(TRACK_COLOR);
- flood_fill(TRK_STRT_X, TRK_STRT_Y + width/2); // the track
- }
-
- void refresh_finish_line()
- {
- set_color(TEXT_COLOR);
- draw_line(finish_x, finish_y_out, finish_x, finish_y_in);
- }
-
- // Put up the scoreboard:
- void scoreboard()
- {
- int i;
-
- double XS = SCORE_BOARD_X;
- double YS = SCORE_BOARD_Y;
- char string[] = "12345678";
- int kount;
-
- spacing = 1.15 * CHR_HGT; // for the leader board only
- // these rectangles are for the leader board car pictures:
- kount = car_count < 5 ? car_count : 5;
- // first erase the old board, if any:
- set_fill_color(FIELD_COLOR);
- rectangle(LDR_BRD_X - 1.9 * CARLEN, LDR_BRD_Y - CHR_HGT,
- LDR_BRD_X + 19*CHR_WID, LDR_BRD_Y - (kount + .7) * spacing);
- set_fill_color(TRACK_COLOR); // rectangular background for car pictures:
- rectangle(LDR_BRD_X - 1.9 * CARLEN, LDR_BRD_Y - CHR_HGT,
- LDR_BRD_X -.5 * CARLEN, LDR_BRD_Y - (kount + .7) * spacing);
- // these rectangles are for the scoreboard car pictures:
- // first erase the old board, if any:
- set_fill_color(FIELD_COLOR);
- rectangle(XS-.7*CARLEN, YS+CHR_HGT/2, XS+13*CHR_WID,
- YS - car_count * CHR_HGT);
- set_fill_color(TRACK_COLOR);
- rectangle(XS-.7*CARLEN, YS+CHR_HGT/2, XS+.5*CARLEN,
- YS - car_count * CHR_HGT);
- // draw the cars on the scoreboard:
- for(i=0; i<car_count; i++) {
- drawcar(XS-.1*CARLEN, YS - i * CHR_HGT - CARWID/2, 0,
- car_colors[i].nose, car_colors[i].tail);
- set_color(TEXT_COLOR);
- itoa(lap_count, string, 10);
- text_output(XS+2*CHR_WID, YS - i * CHR_HGT, namptr[i]);
- (void)lapper(i,-1);
- }
- text_output(XS - 13 * CHR_WID, SCORE_BOARD_Y + 1.5 * CHR_HGT,
- "Race Length Car Driver Laps");
- text_output(LOTIX, LOTIY, "Length of track is ft.");
- itoa(int(length+.5), string, 10);
- text_output(LOTIX + 16.5 * CHR_WID, LOTIY, string);
- itoa(lap_count, string, 10);
- text_output(SCORE_BOARD_X-10*CHR_WID, SCORE_BOARD_Y, string);
- text_output(SCORE_BOARD_X-7*CHR_WID, SCORE_BOARD_Y, "laps");
- text_output(LDR_BRD_X - CHR_WID, LDR_BRD_Y, "LEADERS: max avg");
- text_output(LDR_BRD_X+11.5*CHR_WID, LDR_BRD_Y+CHR_HGT, "mph");
- }
-
- // update the leader board when necessary:
- void leaders(int i)
- {
- char string[] = "12345678";
- double Y;
-
- Y = LDR_BRD_Y - spacing * (i + 1);
-
- // Erase old text:
- set_fill_color(FIELD_COLOR); // The infield color
- rectangle(LDR_BRD_X, Y, LDR_BRD_X+19*CHR_WID, Y - CHR_HGT);
-
- set_color(TEXT_COLOR);
- text_output(LDR_BRD_X, Y, namptr[order[i]]);
- get_max_spd(order[i], string); // the maximum speed:
- text_output(LDR_BRD_X+7.5*CHR_WID, Y, string);
- get_avg_spd(order[i], string); // the average speed:
- text_output(LDR_BRD_X+13.5*CHR_WID, Y, string);
- drawcar(LDR_BRD_X-1.2*CARLEN, Y - CARWID/2, 0.0,
- car_colors[order[i]].nose, car_colors[order[i]].tail);
- }
-